#include "stm32f10x.h"                  // Device header
#include "W25Q64.h"
#include "MySPI.h"
#include "W25Q64_Ins.h"
#include "OLED.h"
#include "Delay.h"
void W25Q64_Init(void)
{
	MySPI_Init();
}

/**
* @brief  读取厂商ID和设备ID，用于验证底层代码书写正确。
	* @param  MID、DID: 分别为主函数中存储厂商ID和设备ID的变量的地址，通过传址调用将它们的值返回
	* @retval None
  */
void W25Q64_ReadID(uint8_t* MID, uint16_t *DID)
{
	MySPI_Start();
	MySPI_SwapByte(W25Q64_JEDEC_ID);//该指令为读ID号，如果一切正确，将会返回设备ID号4017
	*MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);//传输任意数据，返回厂商ID号
	*DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);//传输任意数据，返回设备ID号高8位
	*DID <<= 8;
	*DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);//传输任意数据，返回设备ID号低8位
	MySPI_Stop();
}

/**
* @brief  写使能。
	* @param  None
	* @retval None
  */
void W25Q64_WriteEnable(void)
{
	MySPI_Start();
	MySPI_SwapByte(W25Q64_WRITE_ENABLE);
	MySPI_Stop();
}

/**
* @brief  读状态寄存器并等待，直到芯片不处于忙态
	* @param  None
	* @retval None
  */
void W25Q64_WaitBusy(void)
{
	uint32_t TimeOut = 100000;
	MySPI_Start();
	MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);//执行此命令并返回了一次数据后，如果还不停止，可以再次进行数据交换
	while((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01)
	{
		TimeOut--;
		if(TimeOut == 0)
		{
			OLED_Clear();
			OLED_ShowString(1,1,"Error happened!!!");
			OLED_ShowString(2,1,"TimeOut!!!");
			Delay_s(1);//如因为未知错误导致出现死循环，由此停止程序并报错
			break;
		}
	}//状态寄存器的最低位为1时芯片处于忙态，应继续查看状态，直到忙态解除
	MySPI_Stop();
}

/**
* @brief  页编程。一页至多写入256字节的数据，无论是从头开始写256字节数据，还是从一页中间开始写，没写够256字节就到结尾了，多的都会从该页起始地址开始覆盖。
	* @param  Address：写入地址
	* @param  DataArray[]：存储着待写入数据的数组
	* @param  count：写入数据数量（0至256）
	* @retval None
  */
void W25Q64_PageProgram(uint32_t Address, uint8_t DataArray[], uint16_t count)
{
	W25Q64_WaitBusy();//进行事前等待，直到芯片不处于忙态再开始执行下面的命令
	W25Q64_WriteEnable();//写入前必须先写使能
	MySPI_Start();
	MySPI_SwapByte(W25Q64_PAGE_PROGRAM);
	MySPI_SwapByte(Address >> 16);//地址从高向低传输，此处通过传输三次分别传输其1、2；3、4；5、6位。假设有地址0x123456，此处右移得到0x12
	MySPI_SwapByte(Address >> 8);//此处得到0x1234，同时在传输的过程中又是从低位开始传输的，高位会被舍掉，传输出去的数据为0x34
	MySPI_SwapByte(Address);//传出0x56
	uint16_t i;
	for(i=0;i<count;i++)
	{
		MySPI_SwapByte(DataArray[i]);
	}
	MySPI_Stop();
}

/**
* @brief  扇区擦除
	* @param  Address：所在扇区将会全部被擦除
	* @retval None
  */
void W25Q64_SectorErase(uint32_t Address)
{
	W25Q64_WaitBusy();//进行事前等待，直到芯片不处于忙态再开始执行下面的命令
	W25Q64_WriteEnable();//写入前必须先写使能
	MySPI_Start();
	MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB);
	MySPI_SwapByte(Address >> 16);//地址从高向低传输，此处通过传输三次分别传输其1、2；3、4；5、6位。假设有地址0x123456，此处右移得到0x12
	MySPI_SwapByte(Address >> 8);//此处得到0x1234，同时在传输的过程中又是从低位开始传输的，高位会被舍掉，传输出去的数据为0x34
	MySPI_SwapByte(Address);//传出0x56
	MySPI_Stop();
}

/**
* @brief  读数据
	* @param  Address：读出地址
	* @param  DataArray[]：存储着读出的数据的数组
	* @param  count：写入数据数量，没有页的限制，可以一直读到内存溢出，该数量是可能非常大的
	* @retval None
  */
void W25Q64_ReadData(uint32_t Address, uint8_t DataArray[], uint32_t count)
{
	W25Q64_WaitBusy();//进行事前等待，直到芯片不处于忙态再开始执行下面的命令
	MySPI_Start();
	MySPI_SwapByte(W25Q64_READ_DATA);
	MySPI_SwapByte(Address >> 16);//地址从高向低传输，此处通过传输三次分别传输其1、2；3、4；5、6位。假设有地址0x123456，此处右移得到0x12
	MySPI_SwapByte(Address >> 8);//此处得到0x1234，同时在传输的过程中又是从低位开始传输的，高位会被舍掉，传输出去的数据为0x34
	MySPI_SwapByte(Address);//传出0x56
	uint32_t i;
	for(i=0;i<count;i++)
	{
		DataArray[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	}
	MySPI_Stop();
}
